﻿using Common;
using DadayunApi.Model;
using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace DadayunApi
{
    /// <summary>
    /// 调试模式下,没有连接ERP数据库,Release模式下,需连接ERP数据库
    /// </summary>
    public partial class FormApi:Api
    {
        public FormApi(AppAuthBase authBase, string baseUri) : base(authBase, baseUri)
        {
        }
        /// <summary>
        /// 获取单据模板信息列表
        /// </summary>
        /// <returns></returns>
        public List<FormInfo> GetFormTemplateList()
        {
            List<FormInfo> obj = null;
            var uri = "/v1/form/templates";

            httpStatus = HttpGet(uri);
            
            if (httpStatus == HttpStatusCode.OK)
            {
                obj = JsonConvert.DeserializeObject<List<FormInfo>>(responseJson);
            }
            return obj;
        }
        /// <summary>
        /// 获取单据模板
        /// </summary>
        /// <param name="idOrName">单据模板的ID或者名称</param>
        /// <returns>以Json格式返回单据模板设计</returns>
        public FormTlpInfo GetFormTemplate(string idOrName,int version=-1)
        {
            var uri = "/v1/form/templates/" + idOrName + "?version=" + version;
            httpStatus = HttpGet(uri);
            if (httpStatus == HttpStatusCode.OK)
            {
                return JsonConvert.DeserializeObject<FormTlpInfo>(responseJson);
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 获取单据权限
        /// </summary>
        /// <param name="idOrName"></param>
        /// <param name="includeFieldPermissions">是否包含字段级权限</param>
        /// <returns>权限类实例C-U-R-D-SU(强制编辑)</returns>
        public FormTplPermission GetFormTplPermission(string idOrName,bool includeFieldPermissions=false)
        {
            FormTplPermission obj = null;
            var uri = "/v1/form/templates/" + idOrName + "/permission?field="+includeFieldPermissions;
            httpStatus = HttpGet(uri);
            if (HttpStatus == HttpStatusCode.OK)
            {
                obj = JsonConvert.DeserializeObject<FormTplPermission>(responseJson);
            }
            return obj;
        }
      

        /// <summary>
        /// 获取单据实例列表
        /// </summary>
        /// <param name="idOrName">单据模板Id或者单据模板名称（当keyOption指定Entity时，这里使用单据模板设定的实体名称）</param>
        /// <param name="filter">查询条件json字符串,如 filter=[{"id":"拜访单单号","Operator":"=","value1":"Quotation2017062301"}]</param>
        /// <param name="start">分页开始索引。默认值: 0</param>
        /// <param name="limit">每页数据。默认值: 0，读取全部</param>
        /// <param name="sortField">排序字段(只支持单个字段)，降序前面加-（例如：-CreateTime 表示单据模板列表按创建时间降序）。默认值: -CreateTime</param>
        /// <param name="totalCount">总数</param>
        /// <param name="keyOption">以什么为键名，默认FieldName为键名，Id-以控件Id为键名，Caption-以[组名-]控件名为键名，Entity-以实体属性名为键名。默认值: FieldName</param>
        /// <returns>该表单的实例信息</returns>
        public List<FormInstanceInfo> GetFormList(string idOrName, out int totalCount, int start = 0, int limit = 0, string sortField = "-CreateTime", IEnumerable< FormFilter> filter = null, EKeyOptions keyOption = EKeyOptions.FieldName)
        {
            totalCount = 0;
            List<FormInstanceInfo> obj = new List<FormInstanceInfo>();
            var uri = "/v1/form/templates/" + idOrName + "/instances";
            uri += "?start=" + start + "&count=true&sort=" + sortField + "&keyOption=" + keyOption;
            string sfilter = null;
            if(filter!=null)
            {
                JsonSerializerSettings settings = new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore
                };
                sfilter = JsonConvert.SerializeObject(filter, settings);
                uri += "&filter=" + sfilter;
            }
            totalCount = GetTotalCount(uri);
            if(totalCount>0)
            {
                if (limit == 0)
                    limit = totalCount;
                uri += "&limit=" + limit;
                httpStatus = HttpGet(uri);
                if (httpStatus == HttpStatusCode.OK)
                {
                    obj = JsonConvert.DeserializeObject<List<FormInstanceInfo>>(responseJson);
                }
            }
           
            return obj;
        }

       
        /// <summary>
        /// 获取单据实例
        /// </summary>
        /// <param name="idOrName">单据模板Id或者单据模板名称（当keyOption指定Entity时，使用单据模板设定的实体名称）。</param>
        /// <param name="instanceId">单据实例Id。</param>
        /// <param name="keyOption">以什么为键名，默认FieldName为键名，Id-以控件Id为键名，Caption-以[组名-]控件名为键名，Entity-以实体属性名为键名。默认值: FieldName</param>
        /// <param name="containsAuthority">是否带有授权信息.不带授权信息可以简化模型</param>
        /// <returns>单据实例json</returns>
        public string GetFormInstance(string idOrName,string instanceId,EKeyOptions keyOption=EKeyOptions.FieldName, bool containsAuthority = false)
        {//https://api.dadayun.cn/v1/form/templates/:idOrName/instances/:instanceId

            var uri = "/v1/form/templates/" + idOrName + "/instances/" + instanceId + "?keyOption=" + keyOption;
            uri += "&containsAuthority=" + containsAuthority;

            httpStatus = HttpGet(uri);
            return responseJson;
        }
        /// <summary>
        /// 创建表单实例
        /// 经观察，提交成功后，不管成功创建表单与否，都会返回HttpStatus.OK, 而不会返回 Created
        /// 应该用其他方式来判断是否创建成功，比如判断instanceId是否为空
        /// </summary>
        /// <param name="idOrName">单据模板Id或者单据模板名称（当keyOption指定Entity时，使用单据模板设定的实体名称）。</param>
        /// <param name="jsonFormData">要传输的数据</param>
        /// <param name="isSumit">是否提交，默认提交</param>
        /// <param name="autoFillMode">自动填充模式</param>
        /// <param name="keyOption">字段引用方式</param>
        /// <param name="containsAuthority">输出:创建成功的表单实例Json</param>
        /// <param name="instanceId">输出:创建成功的表单实例ID，如果不成功，此为空值</param>
        /// <returns>创建的表单信息json</returns>
        public HttpStatusCode CreateFormInstance(string idOrName, string jsonFormData,out string instanceId, bool isSumit=true,EAutoFillMode autoFillMode=EAutoFillMode.Null,EKeyOptions keyOption=EKeyOptions.FieldName,bool containsAuthority=false)
        {
            instanceId = "";
            Dictionary<string, string> keyValues = new Dictionary<string, string>
            {
                { "isSubmit", isSumit.ToString() },
                {"autoFillMode",autoFillMode.ToString() },
                { "jsonFormData",jsonFormData},
                { "keyOption",keyOption.ToString()},
                { "containsAuthority",containsAuthority.ToString()},
            };//TODO: 重写该方法
            FormUrlEncodedContent content = new FormUrlEncodedContent(keyValues);
            string uri = "v1/form/templates/" + idOrName + "/instances";//?keyOption="+keyOption+ "&containsAuthority="+ containsAuthority;这两个参数加在URL,不成功
            httpStatus = HttpPost(uri, content);
           
            if(httpStatus == HttpStatusCode.Created|| httpStatus == HttpStatusCode.OK)
            {
                var header = responseHeader.FirstOrDefault(h => h.Key == "Location");
                //heder.value[0]="http://http//api.dadayun.cnhttp://api.dadayun.cn/v1/form/templates/7458fc99-a8e3-4fae-864e-52e67ecb9103/instances/784ddd93-3e44-4321-9e31-6755c6471a47"
                instanceId = header.Value.First().Split(new char[] { '/'},StringSplitOptions.RemoveEmptyEntries).Last();                
            }
            return httpStatus;
        }
        /// <summary>
        /// 修改单据实例
        /// </summary>
        /// <param name="idOrName">单据模板Id或者单据模板名称（当keyOption指定Entity时，这里使用单据模板设定的实体名称）</param>
        /// <param name="instanceId">单据模板Id或者单据模板名称</param>
        /// <param name="jsonFormData">单据实例数据json字符串(key,value格式).例：jsonFormData:{"Bumen":"市场部","BxList":[{"Id":"a7f8affb-632a-4aeb-9549-3be2df8a96ee","Item":"咨询费A","Amount":2400}]}</param>
        /// <param name="isSumit"></param>
        /// <param name="autoFillMode"></param>
        /// <param name="keyOption"></param>
        /// <returns></returns>
        public HttpStatusCode EditFormInstance(string idOrName,string instanceId, string jsonFormData, bool isSumit= true, EAutoFillMode autoFillMode = EAutoFillMode.Null, EKeyOptions keyOption = EKeyOptions.FieldName,bool containsAuthority=true)
        {
            Dictionary<string, string> keyValues = new Dictionary<string, string>
            {
                {"isSubmit", isSumit.ToString() },
                {"autoFillMode",autoFillMode.ToString() },
                {"jsonFormData",jsonFormData},
                {"keyOption",keyOption.ToString()},
                {"containsAuthority",containsAuthority.ToString()}
            };
            FormUrlEncodedContent content = new FormUrlEncodedContent(keyValues);
            string uri = "v1/form/templates/" + idOrName + "/instances/"+ instanceId;
            httpStatus = HttpPut(uri, content);
           
            return httpStatus;
        }
        public HttpStatusCode DeleteFormInstance(string idOrName, string instanceId)
        {
            string uri = "v1/form/templates/" + idOrName + "/instances/" + instanceId;
            return HttpDelete(uri);
        }
     
        
       
        /// <summary>
        /// 批量操作单据实例，用户可以批量新建、修改单据实例数据，批量实例数据之间可以关联（比如实例2需要引用实例1的数据）映射字段。
        /// </summary>
        /// <param name="instances">批量操作单据实例数组，至少包含1条。</param>
        /// <param name="keyOption"></param>
        /// <param name="dataFillMaps">批量操作的单据实例Instances数据关联映射关系。</param>
        /// <returns>成功返回OK,并带回修改过的instances; 没有要更改的数据返回NotModified</returns>
        public HttpStatusCode FormBatchProcessingRestSharp(IEnumerable<BatchInstance> instances, out BatchInstance[] respInstances, EKeyOptions keyOption = EKeyOptions.FieldName, IEnumerable<DataFillMap> dataFillMaps = null)
        {
            if (instances.Count() == 0)
            {
                respInstances = null;
                return HttpStatusCode.NotModified;
            }
            string uri = "/v1/form/instances/batch?keyOption=Entity";
            var client = new RestClient(baseUri);
            var request = new RestRequest(uri, Method.POST);
            request.AddHeader("Authorization", "Bearer " + token.Access_token);
            request.AddHeader("Content-Type", "application/json; charset=utf-8");
            request.RequestFormat = DataFormat.Json;
            request.AddBody(new { Instances = instances , DataFillMaps = dataFillMaps });
            IRestResponse response = client.Execute(request);
            respInstances = null;
            if (response.IsSuccessful)
            {
                responseJson  = response.Content;
                respInstances= JsonConvert.DeserializeObject<BatchInstance[]>(responseJson);
            }
            return response.StatusCode;
        }
    }
    /// <summary>
    /// 批量操作单据实例数组
    /// </summary>
    public class BatchInstance
    {
        /// <summary>
        /// 新建还是修改
        /// </summary>
        public string Action { get; set; } 
        /// <summary>
        /// 表单ID或名称
        /// </summary>
        public string TplIdOrName { get; set; }
        /// <summary>
        /// 所要操作单据实例Id：
        /// 输入参数时: - 如果实例为新建操作，客户端可随机生成唯一Id； 
        ///             - 如果实例为修改操作，必须是该修改的实例Id。
        /// 输出参数时: - 如果实例新建时，客户端随机生成的唯一Id如果不是合法的UUID（Guid），后台自动生成一个UUID；
        ///             - 如果实例为修改操作，原封不动返回该修改的实例Id。
        /// </summary>
        public string InstanceId { get; set; }
        /// <summary>
        /// 所要操作单据实例数据。
        /// </summary>
        public object InstanceData { get; set; }
        public string AutoFillMode { get; set; }
    }
   
    /// <summary>
    /// 映射关系：指定两个不同实体字段间的映射关系
    /// </summary>
    public class   DataFillMap
    {
        /// <summary>
        /// 目标单据实例Id（取Instances[n].InstanceId的值），从源单据实例中映射的字段取值
        /// </summary>
        public string TargetInstanceId { get; set; }
        /// <summary>
        /// 源单据实例Id（取Instances[n].InstanceId的值），填写到目标单据实例中映射的字段；
        /// 如果字段映射中含有自动编码字段，则源单据实例在Instances中的索引需要比目标单据实例所在Instances中的索引小，即排序在目标实例前面。
        /// </summary>
        public string SourceInstanceId { get; set; }
        /// <summary>
        /// 目标单据与源单据的字段映射。数据类型为字典，以目标单据字段名为key，源单据字段名为value。
        /// </summary>
        public Dictionary<string,string> FieldMap { get; set; }
    }
    /// <summary>
    /// 表单查询用的过滤器
    /// </summary>
    public class FormFilter
    {
        /// <summary>
        /// 字段Id或名称，与 keyOption有关。
        /// </summary>
        public string Id { get; set; }
        /// <summary>
        /// 操作符：
        /// - like 包含，默认；
        /// - = 等于；
        /// - <> 不等于；
        /// - > 大于；
        /// - >= 大于或等于；
        /// - 小于、小于或等于涉及特殊字符无法给出，与大于、大于等于类似
        /// - empty 等于字符串空或null；
        /// - range 大于或等于value1并且小于等于value2。
        /// </summary>
        public string Operator { get; set; }
        public string Value1 { get; set; }
        public string Value2 { get; set; }
    }
}
